using System;
using System.Collections.Generic;
using System.Text;
using QiHe.CodeLib;

namespace QiHe.ReliableData
{
    public class TypeDependence
    {
        public static void Resolve(List<DataType> DataTypes)
        {
            Dictionary<String, DataType> Types = new Dictionary<string, DataType>();
            Dictionary<String, Set<String>> Dependence = new Dictionary<string, Set<string>>();
            foreach (DataType dataType in DataTypes)
            {
                Types.Add(dataType.Name, dataType);
                Dependence[dataType.Name] = new Set<string>();
            }
            foreach (DataType dataType in DataTypes)
            {
                foreach (TypeField field in dataType.Fields)
                {
                    string typeName = GetDependentTypeName(field.FieldType);
                    if (Types.ContainsKey(typeName))
                    {
                        Dependence[dataType.Name].Add(typeName);
                    }
                }
            }
            Queue<string> Ordered = new Queue<string>();
            List<string> freeTypes = new List<string>();
            do
            {
                foreach (string typeName in freeTypes)
                {
                    Ordered.Enqueue(typeName);
                    Dependence.Remove(typeName);
                }
                foreach (string typeName in freeTypes)
                {
                    foreach (KeyValuePair<String, Set<String>> pair in Dependence)
                    {
                        pair.Value.Remove(typeName);
                    }
                }
                freeTypes.Clear();
                foreach (KeyValuePair<String, Set<String>> pair in Dependence)
                {
                    if (pair.Value.Count == 0)
                    {
                        freeTypes.Add(pair.Key);
                    }
                }
            }
            while (Dependence.Count > 0 && freeTypes.Count > 0);
            if (Dependence.Count == 0)
            {
                DataTypes.Clear();
                while (Ordered.Count > 0)
                {
                    string typeName = Ordered.Dequeue();
                    DataTypes.Add(Types[typeName]);
                }
            }
            else
            {
                StringBuilder text = new StringBuilder();
                text.AppendLine("Mutual dependence detected:");
                foreach (KeyValuePair<String, Set<String>> pair in Dependence)
                {
                    text.AppendFormat("{0} depends on {1}", pair.Key,
                        StringHelper.ContactWithDelim<string>(pair.Value, ","));
                    text.AppendLine();
                }
                throw new Exception(text.ToString());
            }
        }

        public static string GetDependentTypeName(string fieldTypeName)
        {
            if (fieldTypeName.StartsWith("List<"))
            {
                return fieldTypeName.Substring(5).TrimEnd('>');
            }
            else
            {
                return fieldTypeName;
            }
        }
    }
}
